package com.xavier.dong.netty.dubborpc.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

import java.lang.reflect.Proxy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author XavierDong
 **/
public class NettyClient {

    // 创建线程池
    private static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);

    private static NettyClientHandler nettyClientHandler;

    // 编写 方法，使用 代理模式 获取代理对象
    public Object getBean(final Class<?> service, final String providerName) {

        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[]{service}, (proxy, method, args) -> {


            // 代码 是 客户端 每调用一次 hello 就会 进入 该 代码
            if (nettyClientHandler == null) {

                initClient();
            }
            // 设置 要发给 服务端的信息
            // providerName 协议头  args[0] 就是 客户端 调用 hello(??) 参数
            nettyClientHandler.setParam(providerName + args[0]);
            return EXECUTOR_SERVICE.submit(nettyClientHandler).get();
        });


    }


    // 初始化 客户端
    private static void initClient() {
        nettyClientHandler = new NettyClientHandler();

        // 创建 EventLoopGroup
        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();

        try {
            Bootstrap bootstrap = new Bootstrap();

            bootstrap.group(eventLoopGroup)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {


                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new StringDecoder());
                            pipeline.addLast(new StringEncoder());

                            pipeline.addLast(nettyClientHandler);

                        }
                    });

            ChannelFuture channelFuture = bootstrap.connect("localhost", 7000).sync();

            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            eventLoopGroup.shutdownGracefully();
        }


    }

}
